﻿using Identity.API.Data;
using Identity.API.Data.Models;
using IdentityServer4.Models;
using IdentityServer4.Services;
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using System.Security.Claims;
using IdentityModel;
using System.IdentityModel.Tokens.Jwt;
using Identity.API.Models;

namespace Identity.API.Service
{
    public class ProfileService : IProfileService
    {
        private readonly UserManager<ApplicationUser> userManager;
        public ProfileService(UserManager<ApplicationUser> userManager) //AspNetUserManager<User> userManager)
        {
            this.userManager = userManager;
        }

        private IEnumerable<Claim> GetClaimsForUser(ApplicationUser user)//(User user)
        {
            //var claims = new List<Claim>
            //{
            //    new Claim(JwtClaimTypes.Subject, user.Id.ToString()),
            //    new Claim(JwtClaimTypes.PreferredUserName, user.Name),
            //    new Claim(JwtRegisteredClaimNames.UniqueName, user.Name),
            //    new Claim("name",user.Name)
            //};

            var claims = new List<Claim>
            {
                new Claim(JwtClaimTypes.Subject, user.Id.ToString()),
                new Claim(JwtClaimTypes.PreferredUserName, user.UserName),
                new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)
            };

            if (userManager.SupportsUserEmail)
            {
                claims.AddRange(new[]
                {
                    new Claim(JwtClaimTypes.Email, user.Email),
                    new Claim(JwtClaimTypes.EmailVerified, user.EmailConfirmed ? "true" : "false", ClaimValueTypes.Boolean)
                });
            }

            if (userManager.SupportsUserPhoneNumber && !string.IsNullOrWhiteSpace(user.PhoneNumber))
            {
                claims.AddRange(new[]
                {
                    new Claim(JwtClaimTypes.PhoneNumber, user.PhoneNumber),
                    new Claim(JwtClaimTypes.PhoneNumberVerified, user.PhoneNumberConfirmed ? "true" : "false", ClaimValueTypes.Boolean)
                });
            }

            return claims;
        }

        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            var subject = context.Subject ?? throw new ArgumentNullException(nameof(context.Subject));

            var subjectId = subject.Claims.Where(x => x.Type == "sub").FirstOrDefault().Value;

            //var user = await store.FindByIdAsync(subjectId, new CancellationToken(false));
            var user = await userManager.FindByIdAsync(subjectId);

            if (user == null) throw new ArgumentException("Invalid subject identifier");

            var claims = GetClaimsForUser(user);
            context.IssuedClaims = claims.ToList();

        }

        public async Task IsActiveAsync(IsActiveContext context)
        {
            var subject = context.Subject ?? throw new ArgumentNullException(nameof(context.Subject));

            var subjectId = subject.Claims.Where(x => x.Type == "sub").FirstOrDefault().Value;

            var user = await userManager.FindByIdAsync(subjectId);
            //var user = await store.FindByIdAsync(subjectId, new CancellationToken(false));

            context.IsActive = false;

            if(user != null)
            {
                if (userManager.SupportsUserSecurityStamp)
                {
                    var securityStamp = subject
                                            .Claims
                                            .Where(x => x.Type == "security_stamp")
                                            .Select(c => c.Value)
                                            .SingleOrDefault();
                    if(securityStamp != null)
                    {
                        var db_securityStampp = await userManager.GetSecurityStampAsync(user);
                        if(db_securityStampp != securityStamp)
                        {
                            return;
                        }
                    }
                }

                //context.IsActive = true;
                context.IsActive =
                    !user.LockoutEnabled ||
                    !user.LockoutEnd.HasValue ||
                    user.LockoutEnd <= DateTime.Now;
            }
        }
    }
}
